package ru.papergames.battleserver.model.battle.npc;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author Alexander Troshanin
 */
public class NpcLine {

    private final NpcBattleMap map;

    private final LineVector vector;

    private Set<NpcBall> balls = new HashSet<NpcBall>();

    private NpcCell left;

    private NpcCell right;

    public NpcLine(NpcBattleMap map, LineVector vector) {
        this.map = map;
        this.vector = vector;
    }

    public LineVector getVector() {
        return vector;
    }

    public void addNpcBall(NpcBall npcBall) {
        NpcCell cell = npcBall.getCell();
        if (balls.size() == 0) {
            right = getRightNeighbourCell(cell);
            left = getLeftNeighbourCell(cell);
        } else {
            if (cell == right) {
                right = getRightNeighbourCell(cell);
            } else if (cell == left) {
                left = getLeftNeighbourCell(cell);
            } else {
                System.out.println("[ALARM][NPC-LINE] fuck npc line does not work");
            }
        }
        balls.add(npcBall);
    }

    private NpcCell getRightNeighbourCell(NpcCell cell) {
        NpcCell neighbour = map.getCell(cell.getX() + vector.getDx(), cell.getY() + vector.getDy());
        return neighbour == null ? NpcCell.NULL_CELL : neighbour;
    }

    private NpcCell getLeftNeighbourCell(NpcCell cell) {
        NpcCell neighbour = map.getCell(cell.getX() - vector.getDx(), cell.getY() - vector.getDy());
        return neighbour == null ? NpcCell.NULL_CELL : neighbour;
    }

    public void removeNpcBall(NpcBall npcBall) {
        balls.remove(npcBall);
    }

    public void removeNpcBalls(List<NpcBall> ballsToBeRemoved) {
        balls.removeAll(ballsToBeRemoved);
    }

    public Set<NpcBall> getBalls() {
        return balls;
    }

    public boolean isLineBlocked() {
        return !isLeftCellFree() && !isRightCellFree();
    }

    private boolean isLeftCellFree() {
        return left != null && left != NpcCell.NULL_CELL && left.isCellFree();
    }

    private boolean isRightCellFree() {
        return right != null && right != NpcCell.NULL_CELL && right.isCellFree();
    }

    /**
     * This method is called only in case of merging lines
     * @param newBalls new balls
     */
    public void addNpcBalls(Set<NpcBall> newBalls) {
        for (NpcBall ball : newBalls) {
            if (isNpcBallLefterThenCellOrInCell(ball, left)) {
                left = getLeftNeighbourCell(ball.getCell());
            }
            if (isNpcBallRighterThenCellOrInCell(ball, right)) {
                right = getRightNeighbourCell(ball.getCell());
            }
            balls.add(ball);
            ball.setLine(this);
        }
    }

    private boolean isNpcBallRighterThenCellOrInCell(NpcBall ball, NpcCell cell) {
        return compareBallAndCell(ball, cell) >= 0;
    }

    private boolean isNpcBallLefterThenCellOrInCell(NpcBall ball, NpcCell cell) {
        return compareBallAndCell(ball, cell) <= 0;
    }

    private int compareBallAndCell(NpcBall ball, NpcCell cell) {
        int x0 = cell.getX();
        int y0 = cell.getY();
        int x = ball.getCell().getX();
        int y = ball.getCell().getY();

        return (x - x0) * vector.getDx() + (y - y0) * vector.getDy();
    }

    public NpcCell getLeftBorderCell() {
        return left;
    }

    public NpcCell getRightBorderCell() {
        return right;
    }

    @Override
    public String toString() {
        return "NpcLine{" +
                "vector=" + vector + ", " +
                "size=" + balls.size() +
                '}';
    }
}
